{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g_nWetWWd_ns"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "2pHVBk_seED1"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "N_fMsQ-N8I7j"
      },
      "outputs": [],
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pZJ3uY9O17VN"
      },
      "source": [
        "# Salvataggio e caricamento di modelli"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M4Ata7_wMul1"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/keras/save_and_load\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />Visualizza su TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/it/tutorials/keras/save_and_load.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Esegui in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/it/tutorials/keras/save_and_load.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />Visualizza il sorgente su GitHub</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/it/tutorials/keras/save_and_load.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Scarica il notebook</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BYzaKBe8YXg0"
      },
      "source": [
        "Note: Questi documenti sono stati tradotti dalla nostra comunità di TensorFlow. Poichè queste traduzioni sono *best-effort*, non è garantito che rispecchino in maniera precisa e aggiornata la [documentazione ufficiale in inglese](https://www.tensorflow.org/?hl=en). \n",
        "Se avete suggerimenti per migliorare questa traduzione, mandate per favore una pull request al repository Github [tensorflow/docs](https://github.com/tensorflow/docs). \n",
        "Per proporsi come volontari alla scrittura o alla review delle traduzioni della comunità contattate la \n",
        "[mailing list docs@tensorflow.org](https://groups.google.com/a/tensorflow.org/forum/#!forum/docs)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mBdde4YJeJKF"
      },
      "source": [
        "I cambiamenti dei modelli durante-edopo-l'addestramento possono essere salvati. Ciò significa che un modello può riprendere da dove aveva lasciato, ed evitare lunghi tempi di addestramento. Il salvataggio significa anche che potete condividere il vostro modello ed altri possono ricreare il vostro lavoro. La maggioranza di chi lavora nel machine learning, quando pubblica modelli e tecniche di ricerca, condivide:\n",
        "\n",
        "* il codice per creare il modello, and\n",
        "* i trained weights, o i parametri, per il modello\n",
        "\n",
        "Condividere questi dati aiuta gli altri a capire come lavora il modello e provarlo in autonomia con nuovi dati.\n",
        "\n",
        "Attenzione: Siate cauti con il codice non fidato—i modelli TensorFlow sono codice. Per i dettagli vedere [Uso sicuro di TensorFlow](https://github.com/tensorflow/tensorflow/blob/master/SECURITY.md).\n",
        "\n",
        "### Opzioni\n",
        "\n",
        "Ci sono diversi modi per salvare i modelli TensorFlow—a seconda delle API che state usando. Questa guida usa [tf.keras](https://www.tensorflow.org/guide/keras), un'API di alto livello per costruire e addestrare modelli in TensorFlow. Per altri approcci, vedere la guida [Salvataggio e Ripristino](https://www.tensorflow.org/guide/saved_model) di TensorFlow o [Salvataggio come eager](https://www.tensorflow.org/guide/eager#object-based_saving)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xCUREq7WXgvg"
      },
      "source": [
        "## Setup\n",
        "\n",
        "### Installazioni e importazioni"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7l0MiTOrXtNv"
      },
      "source": [
        "Installare e importare TensorFlow e dipendenze:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RzIOVSdnMYyO"
      },
      "outputs": [],
      "source": [
        "try:\n",
        "  # %tensorflow_version only exists in Colab.\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "  pass\n",
        "\n",
        "!pip install pyyaml h5py  # Required to save models in HDF5 format"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7Nm7Tyb-gRt-"
      },
      "outputs": [],
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "import os\n",
        "\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "\n",
        "print(tf.version.VERSION)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SbGsznErXWt6"
      },
      "source": [
        "### Procuriamoci un dataset di esempio\n",
        "\n",
        "Per dimostrare come salvare e caricare weights, usiamo il [dataset MNIST](http://yann.lecun.com/exdb/mnist/). Per velocizzare il processo, usiamo i primi 1000 esempi:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9rGfFwE9XVwz"
      },
      "outputs": [],
      "source": [
        "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()\n",
        "\n",
        "train_labels = train_labels[:1000]\n",
        "test_labels = test_labels[:1000]\n",
        "\n",
        "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n",
        "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "anG3iVoXyZGI"
      },
      "source": [
        "### Definiamo un modello"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wynsOBfby0Pa"
      },
      "source": [
        "Cominciamo costruendo un semplice modello sequenziale:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0HZbJIjxyX1S"
      },
      "outputs": [],
      "source": [
        "# Define a simple sequential model\n",
        "def create_model():\n",
        "  model = tf.keras.models.Sequential([\n",
        "    keras.layers.Dense(512, activation='relu', input_shape=(784,)),\n",
        "    keras.layers.Dropout(0.2),\n",
        "    keras.layers.Dense(10)\n",
        "  ])\n",
        "\n",
        "  model.compile(optimizer='adam',\n",
        "                loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "                metrics=['accuracy'])\n",
        "\n",
        "  return model\n",
        "\n",
        "# Create a basic model instance\n",
        "model = create_model()\n",
        "\n",
        "# Display the model's architecture\n",
        "model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "soDE0W_KH8rG"
      },
      "source": [
        "## Salvare i punti di controllo durante l'addestramento"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mRyd5qQQIXZm"
      },
      "source": [
        "Potete usare un modello addestrato senza doverlo addestrare di nuovo, o riprendere l'addestramento da dove avevate lasciato, nel caso il processo di addestramento sia stato interrotto. La callback `tf.keras.callbacks.ModelCheckpoint` permette di salvare il modello continuamente sia *durante* sia *alla fine* dell'addestramento.\n",
        "\n",
        "### Utilizzo della callback Checkpoint\n",
        "\n",
        "Creiamo una callback `tf.keras.callbacks.ModelCheckpoint` che salvi i weights solo durante l'addestramento:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IFPuhwntH8VH"
      },
      "outputs": [],
      "source": [
        "checkpoint_path = \"training_1/cp.ckpt\"\n",
        "checkpoint_dir = os.path.dirname(checkpoint_path)\n",
        "\n",
        "# Create a callback that saves the model's weights\n",
        "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n",
        "                                                 save_weights_only=True,\n",
        "                                                 verbose=1)\n",
        "\n",
        "# Train the model with the new callback\n",
        "model.fit(train_images, \n",
        "          train_labels,  \n",
        "          epochs=10,\n",
        "          validation_data=(test_images,test_labels),\n",
        "          callbacks=[cp_callback])  # Pass callback to training\n",
        "\n",
        "# This may generate warnings related to saving the state of the optimizer.\n",
        "# These warnings (and similar warnings throughout this notebook)\n",
        "# are in place to discourage outdated usage, and can be ignored."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rlM-sgyJO084"
      },
      "source": [
        "Ciò crea un'unica collezione di file con i punti di controllo di TensorFlow che vengono salvati alla fine di ogni epoca:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gXG5FVKFOVQ3"
      },
      "outputs": [],
      "source": [
        "!ls {checkpoint_dir}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wlRN_f56Pqa9"
      },
      "source": [
        "Creiamo un nuovo modello, non addestrato. Quando ripristinate un modello dai soli weight, dovete avere un modello con la stessa architettura dell'originale. Dato che l'architettura del modello è la stessa, potete condividere gli weight anche se si tratta di una diversa *istanza* del modello.\n",
        "\n",
        "Ora ricostruiamo una nuova istanza, non addestrata, del modello e valutiamola sull'insieme di test. Un modello non addestrato avrà prestazioni di livello basso (~10% di accuratezza):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Fp5gbuiaPqCT"
      },
      "outputs": [],
      "source": [
        "# Create a basic model instance\n",
        "model = create_model()\n",
        "\n",
        "# Evaluate the model\n",
        "loss, acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Untrained model, accuracy: {:5.2f}%\".format(100*acc))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1DTKpZssRSo3"
      },
      "source": [
        "Ora carichiamo i pesi dal punto di controllo e valutiamo di nuovo:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2IZxbwiRRSD2"
      },
      "outputs": [],
      "source": [
        "# Loads the weights\n",
        "model.load_weights(checkpoint_path)\n",
        "\n",
        "# Re-evaluate the model\n",
        "loss,acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bpAbKkAyVPV8"
      },
      "source": [
        "### Opzioni di callback del punto di controllo\n",
        "\n",
        "La callback mette a disposizione diverse opzioni per dare un nome univoco ai punti di controllo e regolare la loro frequenza.\n",
        "\n",
        "Addestriamo un nuovo modello, e salviamo i checkpoint con un nome univoco ogni cinque epoche:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "mQF_dlgIVOvq"
      },
      "outputs": [],
      "source": [
        "# Include the epoch in the file name (uses `str.format`)\n",
        "checkpoint_path = \"training_2/cp-{epoch:04d}.ckpt\"\n",
        "checkpoint_dir = os.path.dirname(checkpoint_path)\n",
        "\n",
        "# Create a callback that saves the model's weights every 5 epochs\n",
        "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n",
        "    filepath=checkpoint_path, \n",
        "    verbose=1, \n",
        "    save_weights_only=True,\n",
        "    period=5)\n",
        "\n",
        "# Create a new model instance\n",
        "model = create_model()\n",
        "\n",
        "# Save the weights using the `checkpoint_path` format\n",
        "model.save_weights(checkpoint_path.format(epoch=0))\n",
        "\n",
        "# Train the model with the new callback\n",
        "model.fit(train_images, \n",
        "              train_labels,\n",
        "              epochs=50, \n",
        "              callbacks=[cp_callback],\n",
        "              validation_data=(test_images,test_labels),\n",
        "              verbose=0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1zFrKTjjavWI"
      },
      "source": [
        "Ora, guardiamo i punti di controllo che abbiamo ottenuto e prendiamo l'ultimo:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "p64q3-V4sXt0"
      },
      "outputs": [],
      "source": [
        "!ls {checkpoint_dir}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1AN_fnuyR41H"
      },
      "outputs": [],
      "source": [
        "latest = tf.train.latest_checkpoint(checkpoint_dir)\n",
        "latest"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Zk2ciGbKg561"
      },
      "source": [
        "Notare: che il formato standard di tensorflow salva solo i 5 punti di controllo più recenti.\n",
        "\n",
        "Per verificare, riavviamo il modello e carichiamo il checkpoint più recente:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3M04jyK-H3QK"
      },
      "outputs": [],
      "source": [
        "# Create a new model instance\n",
        "model = create_model()\n",
        "\n",
        "# Load the previously saved weights\n",
        "model.load_weights(latest)\n",
        "\n",
        "# Re-evaluate the model\n",
        "loss, acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c2OxsJOTHxia"
      },
      "source": [
        "## Cosa sono questi file?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JtdYhvWnH2ib"
      },
      "source": [
        "Il codice di cui sopra memorizza i pesi in una collezione di file formattati come [checkpoint](https://www.tensorflow.org/guide/saved_model#save_and_restore_variables)-che contengono solo i pesi addestrati in un formato binario. I checkpoint contengono:\n",
        "* Uno o più blocchi che contengono i pesi del nostro modello.\n",
        "* Un file indice che indica quali pesi sono memorizzati in un determinato blocco.\n",
        "\n",
        "Se state solo addestrando un modello su una singola macchina, avrete un blocco con il suffisso: `.data-00000-of-00001`"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "S_FA-ZvxuXQV"
      },
      "source": [
        "## Salvare i pesi manualmente\n",
        "\n",
        "Avete visto come caricare i pesi in un modello. E' semplice salvarli manualmente con il metodo `Model.save_weights`. Per default, in particolare-`tf.keras`—and `save_weights` —usa il formato TensorFlow [checkpoint](../../guide/checkpoint.ipynb) con estensione `.ckpt` (il salvataggio in [HDF5](https://js.tensorflow.org/tutorials/import-keras.html) con estensione `.h5` è trattato nella guida[Salvare e serializzare i modelli](../../guide/keras/save_and_serialize#weights-only_saving_in_savedmodel_format)):"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "R7W5plyZ-u9X"
      },
      "outputs": [],
      "source": [
        "# Save the weights\n",
        "model.save_weights('./checkpoints/my_checkpoint')\n",
        "\n",
        "# Create a new model instance\n",
        "model = create_model()\n",
        "\n",
        "# Restore the weights\n",
        "model.load_weights('./checkpoints/my_checkpoint')\n",
        "\n",
        "# Evaluate the model\n",
        "loss,acc = model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kOGlxPRBEvV1"
      },
      "source": [
        "## Salvare l'intero modello\n",
        "\n",
        "Per salvare l'architettura di un modello, i pesi, e la configurazione di addestramento in un singolo file/cartella, occorre chiamare [`model.save`](https://www.tensorflow.org/api_docs/python/tf/keras/Model#save). Ciò vi permette di esportare un modello in modo che possa essere usato senza accedere al codice* Python originale. Dato che viene ripristinato lo stato dell'ottimizzatore, potrete riprendere l'addestramento esattamente da dove l'avevate lasciato.\n",
        "\n",
        "Un intero modello può essere salvato in due formati di file diversi (SavedModel e HDF). Occorre notare che il formato TensodrFlow SavedModel è il default in TF2.x. Comunque, un modello può essere salvato anche in formato HDF5. Maggiori dettagli sul salvataggio dei modelli nei due formati sono dati in seguito.\n",
        "\n",
        "Il salvataggio di un modello completamente funzionante è molto utile—lo potete caricare in un TensorFlow.js ([HDF5](https://js.tensorflow.org/tutorials/import-keras.html), [Modello Salvato](https://js.tensorflow.org/tutorials/import-saved-model.html)) e poi addestrarlo ed eseguirlo in un browser web, o convertirlo per eseguirlo su un dispositivo mobile usando TensorFlow Lite ([HDF5](https://www.tensorflow.org/lite/convert/python_api#exporting_a_tfkeras_file_), [Modello Salvato](https://www.tensorflow.org/lite/convert/python_api#exporting_a_savedmodel_))\n",
        "\n",
        "\\*Oggetti personalizzati (es. modelli specializzati o livelli) richiedono particolare attenzione durante il salvataggio e il caricamento. Vedere la sezione **Salvataggio di oggetti personalizzati** più sotto"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SkGwf-50zLNn"
      },
      "source": [
        "### formato HDF5\n",
        "\n",
        "Keras fornisce un formato base di salvataggio che usa lo standard [HDF5](https://en.wikipedia.org/wiki/Hierarchical_Data_Format). "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "m2dkmJVCGUia"
      },
      "outputs": [],
      "source": [
        "# Create and train a new model instance.\n",
        "model = create_model()\n",
        "model.fit(train_images, train_labels, epochs=5)\n",
        "\n",
        "# Save the entire model to a HDF5 file.\n",
        "# The '.h5' extension indicates that the model should be saved to HDF5.\n",
        "model.save('my_model.h5') "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GWmttMOqS68S"
      },
      "source": [
        "Ora, ri-creiamo il modello dal file:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5NDMO_7kS6Do"
      },
      "outputs": [],
      "source": [
        "# Recreate the exact same model, including its weights and the optimizer\n",
        "new_model = tf.keras.models.load_model('my_model.h5')\n",
        "\n",
        "# Show the model architecture\n",
        "new_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JXQpbTicTBwt"
      },
      "source": [
        "E controlliamo la sua accuratezza:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jwEaj9DnTCVA"
      },
      "outputs": [],
      "source": [
        "loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print('Restored model, accuracy: {:5.2f}%'.format(100*acc))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dGXqd4wWJl8O"
      },
      "source": [
        "Questa tecnica salva ogni cosa:\n",
        "\n",
        "* I valori dei pesi\n",
        "* L'architettura del modello\n",
        "* La configurazione di addestramento del modello (ciò che avete passato al compilatore)\n",
        "* L'ottimizzatore ed il suo stato, se ce n'è uno (questo è ciò che vi permette di riprendere l'addestramento da dove l'avete lasciato)\n",
        "\n",
        "Keras salva i modelli ispezionando l'architettura. Al momento, esso non è in grado di salvare gli ottimizzatori 'v1.x' (da `tf.compat.v1.train`) in quanto essi non sono compatibili con i punti di controllo. Quando li doveste usare, avrete bisogno di ri-compilare il modello dopo il caricamento, e perderete lo stato dell'ottimizzatore.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kPyhgcoVzqUB"
      },
      "source": [
        "### formato SavedModel"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LtcN4VIb7JkK"
      },
      "source": [
        "Il formato SavedModel è un'altro modo di serializzare i modelli. I modelli salvati in questo formato possono essere ripristinati usando `tf.keras.models.load_model` e sono compatibili con TensorFlow Serving. La [guida SavedModel](https://www.tensorflow.org/guide/saved_model) scende nei dettagli su come utilizzare/ispezionare il SavedModel. La sezione che segue illustra i passi di salvataggio e recupero del modello."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sI1YvCDFzpl3"
      },
      "outputs": [],
      "source": [
        "# Create and train a new model instance.\n",
        "model = create_model()\n",
        "model.fit(train_images, train_labels, epochs=5)\n",
        "\n",
        "# Save the entire model as a SavedModel.\n",
        "!mkdir -p saved_model\n",
        "model.save('saved_model/my_model') "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iUvT_3qE8hV5"
      },
      "source": [
        "Il formato SavedModel è una directory che contiene un binario protobuf ed un checkpoint Tensorflow. Osserviamo la directory del modello salvato:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sq8fPglI1RWA"
      },
      "outputs": [],
      "source": [
        "# my_model directory\n",
        "!ls saved_model\n",
        "\n",
        "# Contains an assets folder, saved_model.pb, and variables folder.\n",
        "!ls saved_model/my_model"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "B7qfpvpY9HCe"
      },
      "source": [
        "Carichiamo un nuovo modello Keras dal modello salvato:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0YofwHdN0pxa"
      },
      "outputs": [],
      "source": [
        "new_model = tf.keras.models.load_model('saved_model/my_model')\n",
        "\n",
        "# Check its architecture\n",
        "new_model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uWwgNaz19TH2"
      },
      "source": [
        "Il modello ripristinato viene compilato con gli stessi argomenti del modello originale. Proviamo ad eseguire, valutare e predire con il modello caricato:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Yh5Mu0yOgE5J"
      },
      "outputs": [],
      "source": [
        "# Evaluate the restored model\n",
        "loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)\n",
        "print('Restored model, accuracy: {:5.2f}%'.format(100*acc))\n",
        "\n",
        "print(new_model.predict(test_images).shape)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kAUKJQyGqTNH"
      },
      "source": [
        "### Salvataggio di oggetti personalizzati\n",
        "\n",
        "Se usate il formato SavedModel potete saltare questa sezione. La differenza chiave tra HDF5 e SavedModel è che HDF5 usa le gli oggetti configs per salvare l'architettura del modello, mentre SavedModel salva il grafo di esecuzione. Così, i SavedModel sono in grado di salvare oggetti personalizzati come modelli derivati per specializzazione e livelli personalizzati senza bisogno del codice originale.\n",
        "\n",
        "Per salvare oggetti personalizzati in HDF5, dovete:\n",
        "\n",
        "1. Definire un metodo `get_config` nel vostro oggetto, e and facoltativamente un classmethod `from_config`.\n",
        "  * `get_config(self)` ritorna un dizionario JSON-serializzabile dei parametri necessari per ri-creare l'oggetto.\n",
        "  * `from_config(cls, config)` usa il config restituito da `get_config` per creare un nuovo oggetto. Per, questa funzione userà il config come kwargs di inizializzazioone (`return cls(**config)`).\n",
        "2. Passare l'oggetto come argomento `custom_objects` al caricamento del modello. L'argomento deve essere un dizionario che mappi la stringa del nome della classe name nella classe Python. Es. `tf.keras.models.load_model(path, custom_objects={'CustomLayer': CustomLayer})`\n",
        "\n",
        "Vedere il tutorial [Scrivere livelli e modelli da zero](https://www.tensorflow.org/guide/keras/custom_layers_and_models) per esempi di oggetti personalizzati e `get_config`.\n"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "save_and_load.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
